#define _WIN32_DCOM
#include <windows.h>
#include <stdio.h>
#include <iaccess.h> // For IAccessControl

// Need to define this ourselves!
const IID IID_IAccessControl = {0xEEDD23E0,0x8410,0x11CE,{0xA1,0xC3,0x08,0x00,0x2B,0x2B,0x8D,0x8F}};

// This is the header stored in the registry
typedef struct
{
    WORD version;
    WORD pad;
    GUID classid;
} SPermissionHeader;

void main()
{
    HRESULT hr = CoInitialize(NULL);
    if(FAILED(hr))
		printf("Couldn't initialize COM\n");

    HKEY key = 0;
    hr = RegOpenKeyEx(HKEY_CLASSES_ROOT, "AppID\\{10000002-0000-0000-0000-000000000001}",
		0, KEY_READ, &key);
    if(FAILED(hr))
	    printf("Couldn't open the AppID key\n");

    // Read the value from the registry
	DWORD dwSize = 0;
    hr = RegQueryValueEx(key, "AccessPermission", NULL, NULL, NULL, &dwSize);
    if(FAILED(hr) || dwSize == 0)
	{
	    printf("Couldn't read the size of the registry value\n");
	    printf("Use DCOMCNFG to configure custom access permissions for the Inside COM+ Sample Component\n");
		exit(0);
	}

	void* pMemory = (void*)CoTaskMemAlloc(dwSize);
    hr = RegQueryValueEx(key, "AccessPermission", NULL, NULL, (unsigned char*)pMemory, &dwSize);
    if(FAILED(hr))
	    printf("Couldn't read the registry value\n");

    IStream* pStream;
    hr = CreateStreamOnHGlobal(pMemory, TRUE, &pStream);
    if(FAILED(hr))
		printf("Couldn't create stream from memory block\n");

	IPersistStream* pPersistStream = NULL;
    hr = CoCreateInstance(CLSID_DCOMAccessControl, NULL, CLSCTX_INPROC_SERVER,
		IID_IPersistStream, (void**)&pPersistStream);
    if(FAILED(hr))
		printf("Couldn't create DCOM access control object\n");

    LARGE_INTEGER size;
    size.QuadPart = sizeof(SPermissionHeader);
    hr = pStream->Seek(size, STREAM_SEEK_SET, NULL);
    if(FAILED(hr))
		printf("Couldn't seek in stream\n");

	hr = pPersistStream->Load(pStream);
    if(FAILED(hr))
		printf("Couldn't load stream\n");

	IAccessControl* pAccessControl = NULL;
	hr = pPersistStream->QueryInterface(IID_IAccessControl, (void**)&pAccessControl);
    if(FAILED(hr))
		printf("Couldn't get IAccessControl\n");

	ACTRL_ACCESSW* pAccess = NULL;
	TRUSTEEW* pOwner = NULL;
	TRUSTEEW* pGroup = NULL;
	hr = pAccessControl->GetAllAccessRights(NULL, &pAccess, &pOwner, &pGroup);
	if(FAILED(hr))
		printf("GetAllAccessRights failed\n");

	printf("ACTRL_ACCESS.Entries = %d\n", pAccess->cEntries);
	for(unsigned count = 0; count < pAccess->cEntries; count++)
	{
		printf("pAccess->pPropertyAccessList[%d].pAccessEntryList->cEntries = %d\n", count, pAccess->pPropertyAccessList[count].pAccessEntryList->cEntries);
		for(unsigned count2 = 0; count2 < pAccess->pPropertyAccessList[count].pAccessEntryList->cEntries; count2++)
		{
			if(pAccess->pPropertyAccessList[count].pAccessEntryList->pAccessList[count2].Trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE)
				printf("pAccessList[%d].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE\n", count2);
			else
				printf("pAccessList[%d].Trustee.MultipleTrusteeOperation = TRUSTEE_IS_IMPERSONATE\n", count2);
			switch(pAccess->pPropertyAccessList[count].pAccessEntryList->pAccessList[count2].Trustee.TrusteeForm)
			{
			case TRUSTEE_IS_SID:
				printf("pAccessList[%d].Trustee.TrusteeForm = TRUSTEE_IS_SID\n", count2);
				/* Add code for SID here if you are interested */
				break;
			case TRUSTEE_IS_NAME:
				printf("pAccessList[%d].Trustee.TrusteeForm = TRUSTEE_IS_NAME\n", count2);
				wprintf(L"pAccessList[%d].Trustee.ptstrName = %s\n", count2, pAccess->pPropertyAccessList[count].pAccessEntryList->pAccessList[count2].Trustee.ptstrName);
				break;
			case TRUSTEE_BAD_FORM:
				printf("pAccessList[%d].Trustee.TrusteeForm = TRUSTEE_BAD_FORM\n", count2);
				break;
			}
			switch(pAccess->pPropertyAccessList[count].pAccessEntryList->pAccessList[count2].Trustee.TrusteeType)
			{
			case TRUSTEE_IS_UNKNOWN:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN\n", count2);
				break;
			case TRUSTEE_IS_USER:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_USER\n", count2);
				break;
			case TRUSTEE_IS_GROUP:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_GROUP\n", count2);
				break;
			case TRUSTEE_IS_DOMAIN:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_DOMAIN\n", count2);
				break;
			case TRUSTEE_IS_ALIAS:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_ALIAS\n", count2);
				break;
			case TRUSTEE_IS_WELL_KNOWN_GROUP:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP\n", count2);
				break;
			case TRUSTEE_IS_DELETED:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_DELETED\n", count2);
				break;
			case TRUSTEE_IS_INVALID:
				printf("pAccessList[%d].Trustee.TrusteeType = TRUSTEE_IS_INVALID\n", count2);
				break;
			}
			if(pAccess->pPropertyAccessList[count].pAccessEntryList->pAccessList[count2].fAccessFlags == ACTRL_ACCESS_ALLOWED)
				printf("pAccessList[%d].fAccessFlags = ACTRL_ACCESS_ALLOWED\n", count2);
			else
				printf("pAccessList[%d].fAccessFlags = ACTRL_ACCESS_DENIED\n", count2);
		}
	}

    // Release everything and bail out
	CoTaskMemFree(pAccess);
	CoTaskMemFree(pOwner);
	CoTaskMemFree(pGroup);

    pPersistStream->Release();
    pStream->Release();
    pAccessControl->Release();

    RegCloseKey(key);
    CoUninitialize();
}